﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

namespace MyTools.DataDic
{
    /// <summary>
    /// 解析PDM文件读取信息
    /// </summary>
    public class PDMReader
    {
        /// <summary>
        /// PDM文件路径
        /// </summary>
        private string _pdmPath;

        /// <summary>
        /// 要读取表的表名,分隔
        /// </summary>
        private string _tableNameList;

        /// <summary>
        /// 校验文件路径是否存在
        /// </summary>
        /// <param name="pdmPath">PDM文件路径</param>
        private void CheckPath(string pdmPath)
        {
            if (string.IsNullOrEmpty(pdmPath))
            {
                throw new Exception("文件路径不能为空！");
            }
            if (!pdmPath.EndsWith(".pdm"))
            {
                throw new Exception("文件格式不正确，请选择PDM文件！");
            }
            if (!File.Exists(pdmPath))
            {
                throw new Exception("指定文件不存在！");
            }
        }

        /// <summary>
        /// 构造函数 根据路径生成所有表的SQL
        /// </summary>
        /// <param name="pdmPath">PDM文件路径</param>
        public PDMReader(string pdmPath)
        {
            try
            {
                CheckPath(pdmPath);
                _pdmPath = pdmPath;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 构造函数 根据路径生成指定表的SQL
        /// </summary>
        /// <param name="pdmPath">PDM文件路径</param>
        /// <param name="tableNameList">表名集合,分隔</param>
        public PDMReader(string pdmPath, string tableNameList)
        {
            try
            {
                CheckPath(pdmPath);
                _pdmPath = pdmPath;
                if (string.IsNullOrEmpty(tableNameList))
                {
                    throw new Exception("表名集合不能为空！");
                }
                _tableNameList = tableNameList;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 从中XML读取表信息
        /// </summary>
        /// <returns> List</returns>
        public List<TableInfo> GetTableInfo()
        {
            try
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(_pdmPath);
                XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(xmlDoc.NameTable);
                xmlnsManager.AddNamespace("a", "attribute");
                xmlnsManager.AddNamespace("c", "collection");
                xmlnsManager.AddNamespace("o", "object");
                XmlNode xnTables = xmlDoc.SelectSingleNode("//" + "c:Tables", xmlnsManager);
                List<TableInfo> Tables = new List<TableInfo>();
                foreach (XmlNode xnTable in xnTables.ChildNodes)
                {
                    Tables.Add(GetTable(xnTable));
                }
                return Tables;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取表信息
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns>表信息</returns>
        public List<TableInfo> GetTableColumnName(string tableName)
        {
            if (string.IsNullOrEmpty(tableName))
            {
                throw new Exception("参数空异常！");
            }
            List<TableInfo> list = GetTableInfo();
            if (list != null && list.Count > 0)
            {
                IEnumerable<TableInfo> query =
                                 from c in list
                                 where c.Code == tableName
                                 select c;
                return query.ToList<TableInfo>();
            }
            return null;
        }

        /// <summary>
        /// 获取节点中表的信息
        /// </summary>
        /// <param name="xnTable">xmlNode</param>
        /// <returns>表信息</returns>
        private TableInfo GetTable(XmlNode xnTable)
        {
            TableInfo mTable = new TableInfo();
            XmlElement xe = (XmlElement)xnTable;
            mTable.TableID = xe.GetAttribute("Id");
            XmlNodeList xnTProperty = xe.ChildNodes;
            foreach (XmlNode xnP in xnTProperty)
            {
                switch (xnP.Name)
                {
                    //表的ID
                    case "a:ObjectID":
                        mTable.TableObjectID = xnP.InnerText;
                        break;
                    //表的中文名称
                    case "a:Name":
                        mTable.Name = xnP.InnerText;
                        break;
                    //表的英文名称
                    case "a:Code":
                        mTable.Code = xnP.InnerText;
                        break;
                    //表的描述
                    case "a:Comment":
                        mTable.Comment = xnP.InnerText;
                        break;
                    //表的列信息
                    case "c:Columns":
                        InitColumns(xnP, mTable);
                        break;
                    //表的主键信息
                    case "c:Keys":
                        InitKeys(xnP, mTable);
                        break;
                    default:
                        break;
                }
            }
            if (string.IsNullOrEmpty(mTable.Comment))
            {
                mTable.Comment = mTable.Name;
            }
            foreach (PkKeyInfo pkInfo in mTable.ListPkKeyInfo)
            {
                ColumnInfo info = mTable.ListColumnInfo.Single(c => c.ColumnId == pkInfo.ColumnId);
                pkInfo.Name = info.Code;
                info.PK = true;
                mTable.PkKeyNameList = mTable.PkKeyNameList + pkInfo.Name + ",";
            }
            if (!string.IsNullOrEmpty(mTable.PkKeyNameList))
            {
                mTable.PkKeyNameList = mTable.PkKeyNameList.Substring(0, mTable.PkKeyNameList.Length - 1);
            }
            return mTable;
        }

        /// <summary>
        /// 获取表中的列信息
        /// </summary>
        /// <param name="xnColumns">列节点</param>
        /// <param name="pTable">表信息</param>
        private void InitColumns(XmlNode xnColumns, TableInfo pTable)
        {
            int i = 1;
            List<ColumnInfo> list = new List<ColumnInfo>();
            pTable.ListColumnInfo = list;
            foreach (XmlNode xnColumn in xnColumns)
            {
                ColumnInfo mColumn = GetColumn(xnColumn);
                mColumn.Sequence = i;
                pTable.ListColumnInfo.Add(mColumn);
                i++;
            }
        }

        /// <summary>
        /// 获取表的主键信息
        /// </summary>
        /// <param name="xnKeys">节点</param>
        /// <param name="pTable">表信息</param>
        private void InitKeys(XmlNode xnKeys, TableInfo pTable)
        {
            List<PkKeyInfo> list = new List<PkKeyInfo>();
            if (xnKeys != null && xnKeys.ChildNodes.Count > 0)
            {
                XmlNode xnKey = xnKeys.ChildNodes[0];
                foreach (XmlNode xnP in xnKey.ChildNodes)
                {
                    if (xnP.Name == "c:Key.Columns")
                    {
                        foreach (XmlNode xn in xnP.ChildNodes)
                        {
                            list.Add(new PkKeyInfo(((XmlElement)xn).GetAttribute("Ref")));
                        }
                    }
                }
            }
            pTable.ListPkKeyInfo = list;
        }


        /// <summary>
        /// 获取列信息
        /// </summary>
        /// <param name="xnColumn">列节点</param>
        /// <returns>列信息</returns>
        private ColumnInfo GetColumn(XmlNode xnColumn)
        {

            ColumnInfo mColumn = new ColumnInfo();
            XmlElement xe = (XmlElement)xnColumn;
            mColumn.ColumnId = xe.GetAttribute("Id");
            XmlNodeList xnCProperty = xe.ChildNodes;
            foreach (XmlNode xnP in xnCProperty)
            {
                switch (xnP.Name)
                {
                    //列ID
                    case "a:ObjectID":
                        mColumn.ColumnObjectId = xnP.InnerText;
                        break;
                    //列中文名称
                    case "a:Name":
                        mColumn.Name = xnP.InnerText;
                        break;
                    //列英文名称
                    case "a:Code":
                        mColumn.Code = xnP.InnerText;
                        break;
                    //列描述
                    case "a:Comment":
                        mColumn.Comment = xnP.InnerText;
                        break;
                    //列数据类型
                    case "a:DataType":
                        mColumn.DataTypeStr = xnP.InnerText;
                        mColumn.DataType = GetColumnDataType(mColumn.DataTypeStr);
                        break;
                    //列宽度
                    case "a:Length":
                        mColumn.Length = xnP.InnerText;
                        break;
                    //列是否自增
                    case "a:Identity":
                        mColumn.Identity = ConvertToBooleanPG(xnP.InnerText);
                        break;
                    //列默认值
                    case "a:DefaultValue":
                        mColumn.DefaultValue = xnP.InnerText;
                        break;
                    //列是否可为空
                    case "a:Mandatory":
                        mColumn.Nullable = ConvertToBooleanPG(xnP.InnerText);
                        break;
                    default:
                        break;
                }
            }
            if (string.IsNullOrEmpty(mColumn.Comment))
            {
                mColumn.Comment = mColumn.Name;
            }
            if (string.IsNullOrEmpty(mColumn.DefaultValue))
            {
                mColumn.DefaultValue = "";
            }
            mColumn.Width = GetColumnWidth(mColumn.DataTypeStr);
            return mColumn;
        }

        /// <summary>
        /// 获取列的数据类型
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns>数据类型</returns>
        private static string GetColumnDataType(string str)
        {
            if (str.Contains("dec"))
            {
                return "decimal";
            }
            else if (str.Contains("datetime"))
            {
                return "datetime";
            }
            else if (str.Contains("uniqueidentifier"))
            {
                return "uniqueidentifier";
            }
            else if (str.Contains("money"))
            {
                return "money";
            }
            else if (str.Contains("int"))
            {
                return str;
            }
            else if (str.Contains("char"))
            {
                return str.Split(new char[] { '(' })[0];
            }
            else if (str.Contains("bit"))
            {
                return "bit";
            }
            else if (str.Contains("binary"))
            {
                return str.Split(new char[] { '(' })[0];
            }
            else
            {
                return str;
            }
        }

        /// <summary>
        /// 获取列的宽度
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns>列宽度</returns>
        private static string GetColumnWidth(string str)
        {
            if (str.Contains("dec"))
            {
                return "0";
            }
            else if (str.Contains("datetime"))
            {
                return "40";
            }
            else if (str.Contains("uniqueidentifier"))
            {
                return "40";
            }
            else if (str.Contains("money"))
            {
                return "40";
            }
            else if (str.Contains("int"))
            {
                return "20";
            }
            else if (str.Contains("char"))
            {
                if (str.Contains("max"))
                {
                    return "-1";
                }
                return str.Split(new char[] { '(' })[1].Replace(")", "");
            }
            else if (str.Contains("bit"))
            {
                return "1";
            }
            else if (str.Contains("binary"))
            {
                if (str.Contains("max"))
                {
                    return "-1";
                }
                return str.Split(new char[] { '(' })[1].Replace(")","");
            }
            else
            {
                return "0";
            }
        }

        /// <summary>
        /// 判断一个对象是否为True
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns>Boolean</returns>
        private static Boolean ConvertToBooleanPG(Object obj)
        {
            if (obj != null)
            {
                string mStr = obj.ToString();
                mStr = mStr.ToLower();
                if ((mStr.Equals("y") || mStr.Equals("1")) || mStr.Equals("true"))
                {
                    return true;
                }
            }
            return false;
        }

    }
}
